package cn.minhx.dtm.starter.core.aspect;

import cn.minhx.dtm.starter.core.annotation.DistributedTransaction;
import cn.minhx.dtm.starter.core.model.InvokeContext;
import cn.minhx.dtm.starter.core.model.TaskStatus;
import cn.minhx.dtm.starter.core.model.TransactionRecord;
import cn.minhx.dtm.starter.core.service.TransactionService;
import com.alibaba.fastjson2.JSON;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * 分布式事务切面 负责拦截带有@DistributedTransaction注解的方法，记录事务信息
 *
 * @author min
 */
@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DistributedTransactionAspect {

	private static final Logger log = LoggerFactory.getLogger(DistributedTransactionAspect.class);

	private final TransactionService transactionService;

	public DistributedTransactionAspect(TransactionService transactionService) {
		this.transactionService = transactionService;
	}

	/** 环绕通知，拦截带有@DistributedTransaction注解的方法 */
	@Around("@annotation(cn.minhx.dtm.starter.core.annotation.DistributedTransaction)")
	public Object processTransaction(ProceedingJoinPoint joinPoint) {
		log.debug("DistributedTransactionAspect: 拦截到分布式事务调用 -> {}", joinPoint.getSignature().toShortString());
		log.debug("DistributedTransactionAspect: 拦截到的类 -> {}", joinPoint.getTarget().getClass().getName());

		// 获取方法信息
		Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
		// 获取注解配置
		DistributedTransaction txAnnotation = method.getAnnotation(DistributedTransaction.class);
		log.debug("DistributedTransactionAspect: 注解配置 -> interval={}, maxRetries={}, async={}", txAnnotation.interval(),
				txAnnotation.maxRetries(), txAnnotation.async());

		// 构建方法调用上下文
		List<String> parameterTypes = Arrays.stream(method.getParameterTypes()).map(Class::getName).toList();

		InvokeContext invokeContext = InvokeContext.builder().className(method.getDeclaringClass().getName())
				.methodName(method.getName()).parameterTypes(parameterTypes.toArray(new String[0]))
				.args(joinPoint.getArgs()).timeout(txAnnotation.timeout()).build();

		// 构建事务记录
		TransactionRecord transactionRecord = TransactionRecord.builder().status(TaskStatus.PENDING.getCode())
				.priority(txAnnotation.priority()).retryCount(0)
				.nextRetryTime(LocalDateTime.now().plusSeconds(txAnnotation.interval()))
				.retryInterval(txAnnotation.interval()).maxRetryCount(txAnnotation.maxRetries())
				.invokeContext(JSON.toJSONString(invokeContext)).deleted(false).build();
		log.debug("DistributedTransactionAspect: 构建事务记录 -> {}", transactionRecord);

		// 提交到事务服务处理
		transactionService.executeTransaction(transactionRecord, txAnnotation.async());
		return null;
	}
}
